package com.googlecode.gaal.vis.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.googlecode.gaal.vis.api.EdgeStyle;
import com.googlecode.gaal.vis.api.NodeStyle;

public class TikzReducedIntervalDrawing extends TikzIntervalDrawing {

    private Map<Integer, TreeNode> terminalNodes = new HashMap<Integer, TreeNode>();
    private List<TreeEdge> terminalEdges = new ArrayList<TreeEdge>();
    private final int terminalExtraDepth;

    public TikzReducedIntervalDrawing(Appendable output, int terminalExtraDepth) {
        super(output);
        this.terminalExtraDepth = terminalExtraDepth;
    }

    public TikzReducedIntervalDrawing(Appendable output, String caption, String label, double scale, double nodeScale,
            int minNodeSize, int terminalExtraDepth) {
        super(output, caption, label, scale, nodeScale, minNodeSize);
        this.terminalExtraDepth = terminalExtraDepth;
    }

    public TikzReducedIntervalDrawing(Appendable output, String caption, String label, String placement, double scale,
            double nodeScale, int minNodeSize, int terminalExtraDepth) {
        super(output, caption, label, placement, scale, nodeScale, minNodeSize);
        this.terminalExtraDepth = terminalExtraDepth;
    }

    @Override
    public int drawNode(int x, int y, String label, NodeStyle style, boolean isTerminal) {
        if (isTerminal) {
            int number = super.incNodeCounter();
            terminalNodes.put(number, new TreeNode(x, y, number, label, style));
            if (y < maxY)
                maxY = y;
            if (x > maxX)
                maxX = x;
            return number;
        } else {
            return appendNode(x, y, label, style);
        }

    }

    @Override
    public void drawEdge(int node, int parent, String label, EdgeStyle style) {
        if (terminalNodes.containsKey(node)) {
            terminalEdges.add(new TreeEdge(node, parent, label, style));
        } else {
            super.drawEdge(node, parent, label, style);
        }
    }

    @Override
    public void flush() throws IOException {
        for (TreeNode node : terminalNodes.values()) {
            appendNode(node.x, maxY - terminalExtraDepth, node.node, node.label, node.style);
        }
        for (TreeEdge edge : terminalEdges) {
            super.drawEdge(edge.node, edge.parent, edge.label, edge.style);
        }
        super.flush();
    }

    class TreeNode {

        public TreeNode(int x, int y, int node, String label, NodeStyle style) {
            this.x = x;
            this.y = y;
            this.node = node;
            this.label = label;
            this.style = style;
        }

        final int x;
        final int y;
        final int node;
        final String label;
        final NodeStyle style;
    }

    class TreeEdge {

        public TreeEdge(int node, int parent, String label, EdgeStyle style) {
            this.node = node;
            this.parent = parent;
            this.label = label;
            this.style = style;
        }

        final int node;
        final int parent;
        final String label;
        final EdgeStyle style;
    }
}
